﻿using System;

namespace Kooboo.CMS.MediaSyncWrapper
{
    using Kooboo.CMS.Content.Models;
    using Kooboo.CMS.Content.Models.Paths;
    using Kooboo.CMS.Content.Services;
    using Kooboo.CMS.Sites.Models;
    using Kooboo.CMS.Sites.Persistence;

    public class MediaFolderManagerWrapper : MediaFolderManager
    {
        public MediaFolderManagerWrapper()
        {
            this.SiteProvider = Kooboo.CMS.Sites.Persistence.Providers.SiteProvider;
        }

        ISiteProvider SiteProvider
        {
            get;
            set;
        }

        #region Base functions facade

        private void BaseAdd(Repository repository, MediaFolder item)
        {
            var folder = this.Get(repository, item.FullName);
            var folderPath = new FolderPath(folder);
            if(!folderPath.Exists())
            {
                EnsureFolder(repository, item);
                base.Add(repository, item);
            }
        }

        private void BaseUpdate(Repository repository, MediaFolder @new, MediaFolder old)
        {
            var oldFolder = this.Get(repository, old.FullName);
            var oldFolderPath = new FolderPath(oldFolder);

            var newFolder = this.Get(repository, @new.FullName);
            var newFolderPath = new FolderPath(newFolder);
            if(oldFolderPath.Exists() && !newFolderPath.Exists())
            {
                EnsureFolder(repository, @new);
                EnsureFolder(repository, old);
                base.Update(repository, @new, old);
            }
        }

        private void BaseRemove(Repository repository, MediaFolder item)
        {
            var folder = this.Get(repository, item.FullName);
            var folderPath = new FolderPath(folder);
            if(folderPath.Exists())
            {
                EnsureFolder(repository, item);
                base.Remove(repository, item);
            }
        }

        private void EnsureFolder(Repository repository, MediaFolder item)
        {
            var parentItem = item.Parent;
            while(parentItem != null)
            {
                parentItem.Repository = repository;
                parentItem = parentItem.Parent;
            }
        }

        #endregion

        public override void Add(Repository repository, MediaFolder item)
        {
            base.Add(repository, item);

            this.SyncToSubSites(
                Site.Current,
                item,
                (Repository, CurrentFolder) =>
                {
                    this.BaseAdd(Repository, CurrentFolder);
                }
            );
        }

        public override void Update(Repository repository, MediaFolder @new, MediaFolder old)
        {
            base.Update(repository, @new, old);

            this.SyncToSubSites(
                Site.Current,
                @new,
                old,
                (Repository, NewFolder, OldFolder) =>
                {
                    this.BaseUpdate(Repository, NewFolder, OldFolder);
                }
            );
        }

        public override void Remove(Repository repository, MediaFolder item)
        {
            base.Remove(repository, item);

            this.SyncToSubSites(
                Site.Current,
                item,
                (Repository, CurrentFolder) =>
                {
                    this.BaseRemove(Repository, CurrentFolder);
                }
            );
        }

        private void SyncToSubSites(Site site, MediaFolder current, Action<Repository, MediaFolder> syncAction)
        {
            foreach(var subSite in this.SiteProvider.ChildSites(site))
            {
                if(syncAction != null)
                {
                    syncAction(subSite.GetRepository(), current);
                }

                this.SyncToSubSites(subSite, current, syncAction);
            }
        }

        private void SyncToSubSites(Site site, MediaFolder @new, MediaFolder old, Action<Repository, MediaFolder, MediaFolder> syncAction)
        {
            foreach(var subSite in this.SiteProvider.ChildSites(site))
            {
                if(syncAction != null)
                {
                    syncAction(subSite.GetRepository(), @new, old);
                }

                this.SyncToSubSites(subSite, @new, old, syncAction);
            }
        }
    }
}